package kz.edu.sdu.itech.pcs.server;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.HashMap;
import java.util.Scanner;

import kz.edu.sdu.itech.pcs.common.Message;
import kz.edu.sdu.itech.pcs.common.MessageType;
import kz.edu.sdu.itech.pcs.common.ServerStatus;

import org.apache.log4j.Logger;

public class Monitor extends Thread implements Runnable {

   static String OK = "OK";
   static Logger log = Logger.getLogger(Monitor.class);

   Socket socket;
   Scanner in;
   PrintWriter out;
   Server server;
//   Thread thread;
   boolean FINISH = false;

   String ip;

   public Monitor(Socket socket, Server server) {
      this.socket = socket;
      this.server = server;
      try {
         in = new Scanner(socket.getInputStream());
         out = new PrintWriter(socket.getOutputStream());
         ip = socket.getInetAddress().getHostAddress();
      } catch (IOException e) {
         e.printStackTrace();
      } finally {
//         server.getWorkerSet().add(this);
//         thread = new Thread(this);
      }
   }

   public void close() {
      try {
         in.close();
         out.close();
         socket.close();
      } catch (IOException e) {
         e.printStackTrace();
      } finally {
//         server.getWorkerSet().remove(this);
      }

   }

   public void say(MessageType mt) {
      Message m = new Message();
      m.setType(mt);
      say(m);
   }

   public String getSomeName() {
      return ip;
   }

   public void say(Message m) {
      out.println(m.toString());
      out.flush();
      if (AppProps.DEBUG)
         log.debug(String.format("say to %s: %s", getSomeName(), m.toString()));
   }

   public MessageFromMonitor readResponse() {
      MessageFromMonitor m = new MessageFromMonitor(this);
      if (m.read())
         return m;
      return null;
   }

   public MessageToMonitor getResponse(MessageFromMonitor req) {
      MessageToMonitor res = new MessageToMonitor(this);
      res.setType(req.getType());
      if (req.getType().equals(MessageType.SETUP)) {
         HashMap<String, String> map = req.getArgs();

         //set alphabet
         String alf = map.get("alphabet");
         Integer len = Integer.parseInt(map.get("len"));
         Integer hash = Integer.parseInt(map.get("hash"));
         if (!server.status.equals(ServerStatus.RUNNING)) {
            server.setupJob(alf, len, hash);
            res.addArg("msg", "OK");
            res.addArg("STATUS", server.status.toString());
         } else {
            res.addArg("msg", "server is running.");
         }
      } else if (req.getType().equals(MessageType.START)) {
         HashMap<String, String> map = req.getArgs();

         //set alphabet
         if (server.workerSet.size() > 0 && !server.status.equals(ServerStatus.RUNNING)) {
            server.startJob();
            res.addArg("STATUS", server.status.toString());
         } else {
            res.addArg("msg", "no working clients.");
         }
      } else if (req.getType().equals(MessageType.STOP)) {
         server.stopJob();
         res.addArg("msg", "OK");
      } else if (req.getType().equals(MessageType.COND)) {

      } else if (req.getType().equals(MessageType.SERVERSTATUS)) {
         res.addArg("STATUS", server.status.toString());
      } else if (req.getType().equals(MessageType.JOB)) {
         ServerJob job = server.currentJob;
         if (job != null) {
            res.addArg("alphabet", job.getAlphabet().toString());
            res.addArg("len", "" + job.getLen());
            res.addArg("hash", "" + job.getHash());
            job.count();
            res.addArg("done", String.format("%.2f", job.getDonePercentage()));
            res.addArg("count", String.format("%d", job.getCount()));
         }
      } else if (req.getType().equals(MessageType.CLIENTS)) {
         int n = server.workerSet.size(), k = 0;
//         res.addArg("CLIENTS", "" + n);
         log.debug("number of workers: " + server.workerSet.size());
         for (Worker e : server.workerSet) {
            res.addArg("" + k, String.format("%s|%s", e.getIp(), e.getTitle()));
            k++;
         }
      }
      return res;
   }

   @Override
   public void run() {
      MessageFromMonitor req = new MessageFromMonitor(this);
      if (req.read()) {
         MessageToMonitor res = getResponse(req);
         while (!AppProps.DONE && !res.send()) {
            try {
               log.debug("Could not send response");
               Thread.sleep(1000);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      }
      sleep(3000);
//      close();

   }

   public static void sleep(int x) {
      try {
         Thread.sleep(x);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }

}
